﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Proggy.Web.Cms.Core.Seo.Service.Abstract;
using Proggy.Web.Cms.Repositories.Published;
using Proggy.Web.Cms.Core.ContentModels;
using Proggy.Web.Cms.Core.Seo.Service.Entities;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Web.Mvc;
using Proggy.Web.Cms.Seo.Service.Abstract;

namespace Proggy.Web.Cms.Core.Seo.Service.Concrete
{
    /// <summary>
    /// Seo site map service
    /// </summary>
    public class SeoSiteMapService : ISeoSiteMapService
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="rootUrl">ie "/"</param>
        /// <param name="frontPartOfUrl">ie "http://mysite.com:503930"</param>
        /// <param name="rootFolderPath">ie C:\\inetpub\wwwroot\mysiteroot\</param>
        public SeoSiteMapService(string rootUrl, string frontPartOfUrl, string rootFolderPath) {
            this.RootUrl = rootUrl;
            this.FrontPartOfUrl = frontPartOfUrl;
            this.RootFolderPath = rootFolderPath;
        }

        /// <summary>
        /// Update site map
        /// </summary>
        /// <param name="contentRepo"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool UpdateXmlSiteMap(IPublishedContentRepository contentRepo, ref string error)
        {
            try
            {
                // get ordered list of content
                var content =
                    contentRepo.GetTypedPublishedContent<ProggyCoreAddressableContentModelBase>(true)
                    .Where(x => x.ContentShouldAppearOnSiteMap && (
                            x.IgnoreInSiteMap == null || !x.IgnoreInSiteMap.SavedValue
                        ))
                    .OrderBy(x => x.OrderInParent)
                    .ThenBy(x => x.LeveInTree)
                    .ThenBy(x => x.OrderInParent)
                    .ToList();

                // get site map collection
                var siteMapData = content.Select(x => this.ConvertToSiteMapModel(x));

                // write
                this.CreateSiteMapXml(siteMapData);

                //
                return true;
            }

            catch (Exception ex)
            {
                error = ex.Message;
                return false;
            }

        }

        /// <summary>
        /// Create xml
        /// </summary>
        /// <param name="siteMapData"></param>
        public void CreateSiteMapXml(IEnumerable<Url> siteMapData)
        {
            // start 
            var xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

            // add parent
            xml.Append("<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">");

            // iterate
            foreach (var url in siteMapData)
            {
                // start
                xml.Append("<url>");

                // location
                xml.Append("<loc>");
                xml.Append(url.loc);
                xml.Append("</loc>");

                // lastmod
                xml.Append("<lastmod>");
                xml.Append(url.lastmod);
                xml.Append("</lastmod>");

                // changefreq
                xml.Append("<changefreq>");
                xml.Append(url.changefreq);
                xml.Append("</changefreq>");

                // location
                xml.Append("<priority>");
                xml.Append(url.priority);
                xml.Append("</priority>");

                // end
                xml.Append("</url>");
            }

            // end parent
            xml.Append("</urlset>");

            // file path
            var filePath = this.RootFolderPath + "sitemap.xml";

            // write
            //File.CreateText(filePath);
            File.WriteAllText(filePath, xml.ToString());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="contentModel"></param>
        /// <returns></returns>
        public Url ConvertToSiteMapModel(ProggyCoreAddressableContentModelBase contentModel)
        {
            // get url
            var url = this.FrontPartOfUrl + this.RootUrl.Substring(0, this.RootUrl.Length - 1) + contentModel.Url;
            
            //
            return new Url
            {
                //ChangeFrequency = contentModel.SiteMapChangeFrequency,
                changefreq = contentModel.SiteMapChangeFrequency.ToString().ToLower(),
                //LastModified = contentModel.LastUpdated,
                lastmod = contentModel.LastUpdated.ToString("yyyy-MM-ddTHH:mm:ss.fffK"),
                //Location = new Uri(rootUrl.Substring(0, rootUrl.Length - 1) + contentModel.Url),
                loc = url,
                //Priority = Convert.ToSingle(this.GetPriorityFromEnum(contentModel.SiteMapPriority)),
                priority = this.GetPriorityFromEnum(contentModel.SiteMapPriority)
            };
        }

        /// <summary>
        /// Return priority string from enum
        /// </summary>
        /// <param name="siteMapPriorityEnum"></param>
        /// <returns></returns>
        public string GetPriorityFromEnum(SiteMapPriorityEnum siteMapPriorityEnum)
        {
            switch (siteMapPriorityEnum)
            {
                case SiteMapPriorityEnum.One: return "1.0";
                case SiteMapPriorityEnum.ZeroPoint1: return "0.1";
                case SiteMapPriorityEnum.ZeroPoint2: return "0.2";
                case SiteMapPriorityEnum.ZeroPoint3: return "0.3";
                case SiteMapPriorityEnum.ZeroPoint4: return "0.4";
                case SiteMapPriorityEnum.ZeroPoint5: return "0.5";
                case SiteMapPriorityEnum.ZeroPoint6: return "0.6";
                case SiteMapPriorityEnum.ZeroPoint7: return "0.7";
                case SiteMapPriorityEnum.ZeroPoint8: return "0.8";
                case SiteMapPriorityEnum.ZeroPoint9: return "0.9";
                default: return "0.5";
            }
        }

        /// <summary>
        /// Web root folder path
        /// </summary>
        public string RootFolderPath { get; set; }

        /// <summary>
        /// Front part of url
        /// </summary>
        public string FrontPartOfUrl { get; set; }

        /// <summary>
        /// Root url
        /// </summary>
        public string RootUrl { get; set; }
    }
}
